<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Title</title>
    
    <style>
      .carousel-container {
        border: 1px gray solid;
        border-radius: 10px;
        padding: 20px;
        display: grid;
        grid-template-columns: repeat(2, 1fr);
        column-gap: 15px;
        row-gap: 15px;
        width: 400px;
        height: 320px;
        overflow-y: auto;
        scroll-snap-type: y mandatory;
      }
      
      .carousel-container::-webkit-scrollbar { /* 滚动条整体样式 */
        width: 4px;
        background-color: transparent;
      }
      
      .carousel-container::-webkit-scrollbar-thumb { /* 滚动条里面小方块 */
        width: 4px;
        background: #7D7E7D;
        border-radius: 2px;
      }
      
      .carousel-container-son {
        height: 90px;
        background: darkgray;
        color: white;
        display: flex;
        justify-content: center;
        align-items: center;
        font-size: 25px;
        scroll-margin: 15px;
      }
    </style>
  
  </head>
  
  <body>
    <!--
      1.为滚动容器设置宽度或高度、X或Y轴滚动条
      2.为滚动容器设置scroll-snap-type，根据需要为滚动子元素添加scroll-snap-align
      3.创建定时器，每次为滚动容器设置轮播距离scrollTop，该距离根据实际轮播需要设置
      4.鼠标移入onmouseenter和移出onmouseleave时，分别暂停和开始轮询
      5.手动移动滚动条后onscrollend轮播从当前位置开始
    -->
    <div
      class="carousel-container"
      onmouseenter="endCarrouselInterval()"
      onmouseleave="startCarrouselInterval()"
    >
      <div class="carousel-container-son" style="scroll-snap-align: start">1</div>
      <div class="carousel-container-son">2</div>
      <div class="carousel-container-son">3</div>
      <div class="carousel-container-son">4</div>
      <div class="carousel-container-son">5</div>
      <div class="carousel-container-son">6</div>
      
      <div class="carousel-container-son" style="scroll-snap-align: start">7</div>
      <div class="carousel-container-son">8</div>
      <div class="carousel-container-son">9</div>
      <div class="carousel-container-son">10</div>
      <div class="carousel-container-son">11</div>
      <div class="carousel-container-son">12</div>
      
      <div class="carousel-container-son" style="scroll-snap-align: start">13</div>
      <div class="carousel-container-son">14</div>
      <div class="carousel-container-son">15</div>
      <div class="carousel-container-son">16</div>
      <div class="carousel-container-son">17</div>
      <div class="carousel-container-son">18</div>
      
      <div class="carousel-container-son" style="scroll-snap-align: start">19</div>
      <div class="carousel-container-son">20</div>
      <div class="carousel-container-son">21</div>
      <div class="carousel-container-son">22</div>
      <div class="carousel-container-son">23</div>
      <div class="carousel-container-son">24</div>
      
      <div class="carousel-container-son" style="scroll-snap-align: start">25</div>
      <div class="carousel-container-son">26</div>
      <div class="carousel-container-son">27</div>
      <div class="carousel-container-son">28</div>
      <div class="carousel-container-son">29</div>
      <div class="carousel-container-son">30</div>
      
      <div class="carousel-container-son" style="scroll-snap-align: start">31</div>
      <div class="carousel-container-son">32</div>
      <div class="carousel-container-son">33</div>
    </div>
  </body>
  
  <script>
    let carouselInterval = null;
    let currentCarouselIndex = 0;
    let carrouselGroupTotal = 5;
    let scrollStep = 320;
    let scrollPosition = 0;
    
    // 开始轮播
    function startCarrouselInterval() {
      carouselInterval = setInterval(() => {
        // 移动滚动条
        scrollPosition += scrollStep;
        if (currentCarouselIndex === 0) {
          scrollPosition = 0;
        }
        const carouselContainer = document.querySelector('.carousel-container');
        carouselContainer.scrollTo({
          top: scrollPosition,
          behavior: 'smooth',
        });
        
        // 移动当前轮播索引
        currentCarouselIndex = currentCarouselIndex + 1;
        if (currentCarouselIndex === carrouselGroupTotal) {
          currentCarouselIndex = 0;
        }
      }, 4000);
    }
    
    // 结束轮播
    function endCarrouselInterval() {
      clearInterval(carouselInterval);
      carouselInterval = null;
    }
    
    // 手动移动滚动条
    const carouselContainer = document.querySelector('.carousel-container');
    carouselContainer.onscrollend = (e) => {
      // 手动移动滚动条后当前组的索引
      const num = e.target.scrollTop / scrollStep;
      let groupIndex = Math.round(num);
      
      // 最后一组不满导致无法手动触发加载问题
      let scrollTop = Math.round(num) * scrollStep;
      scrollTop =
        Math.abs(e.target.scrollTop - scrollTop) <= 5
          ? scrollTop
          : e.target.scrollTop;
      if (groupIndex !== Math.ceil(num) && !Number.isInteger(scrollTop)) {
        // 不是整数则是最后一组
        groupIndex += 1;
      }
      
      // 手动移动滚动条
      if (carouselInterval === null) {
        // 滚动条未发生改变则返回
        if (groupIndex === currentCarouselIndex) {
          return;
        }
        
        // 移动当前轮播索引
        currentCarouselIndex = currentCarouselIndex + 1;
        if (currentCarouselIndex === carrouselGroupTotal) {
          currentCarouselIndex = 0;
        }
        
        // 更新滚动条位置
        scrollPosition = groupIndex * scrollStep;
      }
    };
    
    startCarrouselInterval();
  </script>
</html>